summaryrefslogtreecommitdiffstats
path: root/glucometerutils/drivers/otultra2.py
diff options
context:
space:
mode:
Diffstat (limited to 'glucometerutils/drivers/otultra2.py')
-rw-r--r--glucometerutils/drivers/otultra2.py386
1 files changed, 193 insertions, 193 deletions
diff --git a/glucometerutils/drivers/otultra2.py b/glucometerutils/drivers/otultra2.py
index 762991e..a27d333 100644
--- a/glucometerutils/drivers/otultra2.py
+++ b/glucometerutils/drivers/otultra2.py
@@ -57,273 +57,273 @@ _DUMP_LINE_RE = re.compile(
_RESPONSE_MATCH = re.compile(r'^(.+) ([0-9A-F]{4})\r$')
def _calculate_checksum(bytestring):
- """Calculate the checksum used by OneTouch Ultra and Ultra2 devices
+ """Calculate the checksum used by OneTouch Ultra and Ultra2 devices
- Args:
- bytestring: the string of which the checksum has to be calculated.
+ Args:
+ bytestring: the string of which the checksum has to be calculated.
- Returns:
- A string with the hexdecimal representation of the checksum for the input.
+ Returns:
+ A string with the hexdecimal representation of the checksum for the input.
- The checksum is a very stupid one: it just sums all the bytes,
- modulo 16-bit, without any parity.
- """
- checksum = 0
+ The checksum is a very stupid one: it just sums all the bytes,
+ modulo 16-bit, without any parity.
+ """
+ checksum = 0
- for byte in bytestring:
- checksum = (checksum + byte) & 0xffff
+ for byte in bytestring:
+ checksum = (checksum + byte) & 0xffff
- return checksum
+ return checksum
def _validate_and_strip_checksum(line):
- """Verify the simple 16-bit checksum and remove it from the line.
+ """Verify the simple 16-bit checksum and remove it from the line.
- Args:
- line: the line to check the checksum of.
+ Args:
+ line: the line to check the checksum of.
- Returns:
- A copy of the line with the checksum stripped out.
- """
- match = _RESPONSE_MATCH.match(line)
+ Returns:
+ A copy of the line with the checksum stripped out.
+ """
+ match = _RESPONSE_MATCH.match(line)
- if not match:
- raise lifescan.MissingChecksum(line)
+ if not match:
+ raise lifescan.MissingChecksum(line)
- response, checksum_string = match.groups()
+ response, checksum_string = match.groups()
- try:
- checksum_given = int(checksum_string, 16)
- checksum_calculated = _calculate_checksum(
- bytes(response, 'ascii'))
+ try:
+ checksum_given = int(checksum_string, 16)
+ checksum_calculated = _calculate_checksum(
+ bytes(response, 'ascii'))
- if checksum_given != checksum_calculated:
- raise exceptions.InvalidChecksum(checksum_given,
- checksum_calculated)
- except ValueError:
- raise exceptions.InvalidChecksum(checksum_given, None)
+ if checksum_given != checksum_calculated:
+ raise exceptions.InvalidChecksum(checksum_given,
+ checksum_calculated)
+ except ValueError:
+ raise exceptions.InvalidChecksum(checksum_given, None)
- return response
+ return response
_DATETIME_RE = re.compile(
r'^"[A-Z]{3}","([0-9]{2}/[0-9]{2}/[0-9]{2})","([0-9]{2}:[0-9]{2}:[0-9]{2}) "$')
def _parse_datetime(response):
- """Convert a response with date and time from the meter into a datetime.
+ """Convert a response with date and time from the meter into a datetime.
- Args:
- response: the response coming from a DMF or DMT command
+ Args:
+ response: the response coming from a DMF or DMT command
- Returns:
- A datetime object built according to the returned response.
+ Returns:
+ A datetime object built according to the returned response.
- Raises:
- InvalidResponse if the string cannot be matched by _DATETIME_RE.
- """
- match = _DATETIME_RE.match(response)
- if not match:
- raise exceptions.InvalidResponse(response)
+ Raises:
+ InvalidResponse if the string cannot be matched by _DATETIME_RE.
+ """
+ match = _DATETIME_RE.match(response)
+ if not match:
+ raise exceptions.InvalidResponse(response)
- date, time = match.groups()
- month, day, year = map(int, date.split('/'))
- hour, minute, second = map(int, time.split(':'))
+ date, time = match.groups()
+ month, day, year = map(int, date.split('/'))
+ hour, minute, second = map(int, time.split(':'))
- # Yes, OneTouch2's firmware is not Y2K safe.
- return datetime.datetime(2000 + year, month, day, hour, minute, second)
+ # Yes, OneTouch2's firmware is not Y2K safe.
+ return datetime.datetime(2000 + year, month, day, hour, minute, second)
class Device(serial.SerialDevice):
- BAUDRATE = 9600
- DEFAULT_CABLE_ID = '067b:2303' # Generic PL2303 cable.
+ BAUDRATE = 9600
+ DEFAULT_CABLE_ID = '067b:2303' # Generic PL2303 cable.
- def connect(self):
- return
+ def connect(self):
+ return
- def disconnect(self):
- return
+ def disconnect(self):
+ return
- def _send_command(self, cmd):
- """Send command interface.
+ def _send_command(self, cmd):
+ """Send command interface.
- Args:
- cmd: command and parameters to send (without newline)
- """
- cmdstring = bytes('\x11\r' + cmd + '\r', 'ascii')
- self.serial_.write(cmdstring)
- self.serial_.flush()
+ Args:
+ cmd: command and parameters to send (without newline)
+ """
+ cmdstring = bytes('\x11\r' + cmd + '\r', 'ascii')
+ self.serial_.write(cmdstring)
+ self.serial_.flush()
- def _send_oneliner_command(self, cmd):
- """Send command and read a one-line response.
+ def _send_oneliner_command(self, cmd):
+ """Send command and read a one-line response.
- Args:
- cmd: command and parameters to send (without newline)
+ Args:
+ cmd: command and parameters to send (without newline)
- Returns:
- A single line of text that the glucometer responds, without the checksum.
- """
- self._send_command(cmd)
+ Returns:
+ A single line of text that the glucometer responds, without the checksum.
+ """
+ self._send_command(cmd)
- line = self.serial_.readline().decode('ascii')
- return _validate_and_strip_checksum(line)
+ line = self.serial_.readline().decode('ascii')
+ return _validate_and_strip_checksum(line)
- def get_meter_info(self):
- """Fetch and parses the device information.
+ def get_meter_info(self):
+ """Fetch and parses the device information.
- Returns:
- A common.MeterInfo object.
- """
- return common.MeterInfo(
- 'OneTouch Ultra 2 glucometer',
- serial_number=self.get_serial_number(),
- version_info=(
- 'Software version: ' + self.get_version(),),
- native_unit=self.get_glucose_unit())
+ Returns:
+ A common.MeterInfo object.
+ """
+ return common.MeterInfo(
+ 'OneTouch Ultra 2 glucometer',
+ serial_number=self.get_serial_number(),
+ version_info=(
+ 'Software version: ' + self.get_version(),),
+ native_unit=self.get_glucose_unit())
- def get_version(self):
- """Returns an identifier of the firmware version of the glucometer.
+ def get_version(self):
+ """Returns an identifier of the firmware version of the glucometer.
- Returns:
- The software version returned by the glucometer, such as
- "P02.00.00 30/08/06".
- """
- response = self._send_oneliner_command('DM?')
+ Returns:
+ The software version returned by the glucometer, such as
+ "P02.00.00 30/08/06".
+ """
+ response = self._send_oneliner_command('DM?')
- if response[0] != '?':
- raise exceptions.InvalidResponse(response)
+ if response[0] != '?':
+ raise exceptions.InvalidResponse(response)
- return response[1:]
+ return response[1:]
- _SERIAL_NUMBER_RE = re.compile('^@ "([A-Z0-9]{9})"$')
+ _SERIAL_NUMBER_RE = re.compile('^@ "([A-Z0-9]{9})"$')
- def get_serial_number(self):
- """Retrieve the serial number of the device.
+ def get_serial_number(self):
+ """Retrieve the serial number of the device.
- Returns:
- A string representing the serial number of the device.
+ Returns:
+ A string representing the serial number of the device.
- Raises:
- exceptions.InvalidResponse: if the DM@ command returns a string not
- matching _SERIAL_NUMBER_RE.
- InvalidSerialNumber: if the returned serial number does not match
- the OneTouch2 device as per specs.
- """
- response = self._send_oneliner_command('DM@')
+ Raises:
+ exceptions.InvalidResponse: if the DM@ command returns a string not
+ matching _SERIAL_NUMBER_RE.
+ InvalidSerialNumber: if the returned serial number does not match
+ the OneTouch2 device as per specs.
+ """
+ response = self._send_oneliner_command('DM@')
- match = self._SERIAL_NUMBER_RE.match(response)
- if not match:
- raise exceptions.InvalidResponse(response)
+ match = self._SERIAL_NUMBER_RE.match(response)
+ if not match:
+ raise exceptions.InvalidResponse(response)
- serial_number = match.group(1)
+ serial_number = match.group(1)
- # 'Y' at the far right of the serial number is the indication of a OneTouch
- # Ultra2 device, as per specs.
- if serial_number[-1] != 'Y':
- raise lifescan.InvalidSerialNumber(serial_number)
+ # 'Y' at the far right of the serial number is the indication of a OneTouch
+ # Ultra2 device, as per specs.
+ if serial_number[-1] != 'Y':
+ raise lifescan.InvalidSerialNumber(serial_number)
- return serial_number
+ return serial_number
- def get_datetime(self):
- """Returns the current date and time for the glucometer.
+ def get_datetime(self):
+ """Returns the current date and time for the glucometer.
- Returns:
- A datetime object built according to the returned response.
- """
- response = self._send_oneliner_command('DMF')
- return _parse_datetime(response[2:])
+ Returns:
+ A datetime object built according to the returned response.
+ """
+ response = self._send_oneliner_command('DMF')
+ return _parse_datetime(response[2:])
- def set_datetime(self, date=datetime.datetime.now()):
- """Sets the date and time of the glucometer.
+ def set_datetime(self, date=datetime.datetime.now()):
+ """Sets the date and time of the glucometer.
- Args:
- date: The value to set the date/time of the glucometer to. If none is
- given, the current date and time of the computer is used.
+ Args:
+ date: The value to set the date/time of the glucometer to. If none is
+ given, the current date and time of the computer is used.
- Returns:
- A datetime object built according to the returned response.
- """
- response = self._send_oneliner_command(
- 'DMT' + date.strftime('%m/%d/%y %H:%M:%S'))
+ Returns:
+ A datetime object built according to the returned response.
+ """
+ response = self._send_oneliner_command(
+ 'DMT' + date.strftime('%m/%d/%y %H:%M:%S'))
- return _parse_datetime(response[2:])
+ return _parse_datetime(response[2:])
- def zero_log(self):
- """Zeros out the data log of the device.
+ def zero_log(self):
+ """Zeros out the data log of the device.
- This function will clear the memory of the device deleting all the readings
- in an irrecoverable way.
- """
- response = self._send_oneliner_command('DMZ')
- if response != 'Z':
- raise exceptions.InvalidResponse(response)
+ This function will clear the memory of the device deleting all the readings
+ in an irrecoverable way.
+ """
+ response = self._send_oneliner_command('DMZ')
+ if response != 'Z':
+ raise exceptions.InvalidResponse(response)
- _GLUCOSE_UNIT_RE = re.compile(r'^SU\?,"(MG/DL |MMOL/L)"')
+ _GLUCOSE_UNIT_RE = re.compile(r'^SU\?,"(MG/DL |MMOL/L)"')
- def get_glucose_unit(self):
- """Returns a constant representing the unit displayed by the meter.
+ def get_glucose_unit(self):
+ """Returns a constant representing the unit displayed by the meter.
- Returns:
- common.Unit.MG_DL: if the glucometer displays in mg/dL
- common.Unit.MMOL_L: if the glucometer displays in mmol/L
+ Returns:
+ common.Unit.MG_DL: if the glucometer displays in mg/dL
+ common.Unit.MMOL_L: if the glucometer displays in mmol/L
- Raises:
- exceptions.InvalidGlucoseUnit: if the unit is not recognized
+ Raises:
+ exceptions.InvalidGlucoseUnit: if the unit is not recognized
- OneTouch meters will always dump data in mg/dL because that's their internal
- storage. They will then provide a separate method to read the unit used for
- display. This is not settable by the user in all modern meters.
+ OneTouch meters will always dump data in mg/dL because that's their internal
+ storage. They will then provide a separate method to read the unit used for
+ display. This is not settable by the user in all modern meters.
- """
- response = self._send_oneliner_command('DMSU?')
+ """
+ response = self._send_oneliner_command('DMSU?')
- match = self._GLUCOSE_UNIT_RE.match(response)
- unit = match.group(1)
+ match = self._GLUCOSE_UNIT_RE.match(response)
+ unit = match.group(1)
- if unit == 'MG/DL ':
- return common.Unit.MG_DL
- elif unit == 'MMOL/L':
- return common.Unit.MMOL_L
- else:
- raise exceptions.InvalidGlucoseUnit(string)
+ if unit == 'MG/DL ':
+ return common.Unit.MG_DL
+ elif unit == 'MMOL/L':
+ return common.Unit.MMOL_L
+ else:
+ raise exceptions.InvalidGlucoseUnit(string)
- def get_readings(self):
- """Iterates over the reading values stored in the glucometer.
+ def get_readings(self):
+ """Iterates over the reading values stored in the glucometer.
- Args:
- unit: The glucose unit to use for the output.
+ Args:
+ unit: The glucose unit to use for the output.
- Yields:
- A tuple (date, value) of the readings in the glucometer. The value is a
- floating point in the unit specified; if no unit is specified, the default
- unit in the glucometer will be used.
+ Yields:
+ A tuple (date, value) of the readings in the glucometer. The value is a
+ floating point in the unit specified; if no unit is specified, the default
+ unit in the glucometer will be used.
- Raises:
- exceptions.InvalidResponse: if the response does not match what expected.
- """
- self._send_command('DMP')
- data = self.serial_.readlines()
+ Raises:
+ exceptions.InvalidResponse: if the response does not match what expected.
+ """
+ self._send_command('DMP')
+ data = self.serial_.readlines()
- header = data.pop(0).decode('ascii')
- match = _DUMP_HEADER_RE.match(header)
- if not match:
- raise exceptions.InvalidResponse(header)
+ header = data.pop(0).decode('ascii')
+ match = _DUMP_HEADER_RE.match(header)
+ if not match:
+ raise exceptions.InvalidResponse(header)
- count = int(match.group(1))
- assert count == len(data)
+ count = int(match.group(1))
+ assert count == len(data)
- for line in data:
- line = _validate_and_strip_checksum(line.decode('ascii'))
+ for line in data:
+ line = _validate_and_strip_checksum(line.decode('ascii'))
- match = _DUMP_LINE_RE.match(line)
- if not match:
- raise exceptions.InvalidResponse(line)
+ match = _DUMP_LINE_RE.match(line)
+ if not match:
+ raise exceptions.InvalidResponse(line)
- line_data = match.groupdict()
+ line_data = match.groupdict()
- date = _parse_datetime(line_data['datetime'])
- meal = _MEAL_CODES[line_data['meal']]
- comment = _COMMENT_CODES[line_data['comment']]
+ date = _parse_datetime(line_data['datetime'])
+ meal = _MEAL_CODES[line_data['meal']]
+ comment = _COMMENT_CODES[line_data['comment']]
- # OneTouch2 always returns the data in mg/dL even if the glucometer is set
- # to mmol/L, so there is no conversion required.
- yield common.GlucoseReading(
- date, float(line_data['value']), meal=meal, comment=comment)
+ # OneTouch2 always returns the data in mg/dL even if the glucometer is set
+ # to mmol/L, so there is no conversion required.
+ yield common.GlucoseReading(
+ date, float(line_data['value']), meal=meal, comment=comment)